package org.streets.workflow.engine.extension;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.streets.workflow.engine.IProcessTrace;
import org.streets.workflow.engine.IToken;
import org.streets.workflow.engine.ITransition;
import org.streets.workflow.engine.WorkflowContext;
import org.streets.workflow.engine.WorkflowException;
import org.streets.workflow.engine.condition.ConditionConstant;
import org.streets.workflow.engine.condition.IConditionResolver;
import org.streets.workflow.engine.entities.ProcessTrace;
import org.streets.workflow.engine.entities.ProcessVariant;
import org.streets.workflow.engine.event.EdgeEvent;
import org.streets.workflow.engine.event.IEdgeEventListener;
import org.streets.workflow.engine.mem.Transition;
import org.streets.workflow.engine.plugin.INodeNetExtension;
import org.streets.workflow.model.WFElement;
import org.streets.workflow.model.net.WFActivity;
import org.streets.workflow.model.net.WFTransition;

/**
 *
 * @author chennieyun
 */
public class TransitionExtension implements INodeNetExtension, IEdgeEventListener {

    protected WorkflowContext rtCtx = null;

    public void setRuntimeContext(WorkflowContext ctx) {
        this.rtCtx = ctx;
    }

    public WorkflowContext getRuntimeContext() {
        return this.rtCtx;
    }

    /**
     * 执行分支判断策略，即设置token的alive属性 首先，如果this.alive==false,则所有的token的Alive属性皆为false
     * 然后，如果在nexttransitionList中有值，则直接执行列表中的tansition
     * 否则，通过计算Transition的表达式来确定下一个transition,
     * 
     * @param transInst
     * @return
     */
    private boolean determineTheAliveOfToken(String condition, List<ProcessVariant> vars) throws Exception{

        // 通过计算transition上的表达式来确定alive的值
    	Map<String, Object> var_map = new HashMap<String, Object>();
    	for (ProcessVariant var : vars) {
    		var_map.put(var.getName(), var.getValue());
    	}
        IConditionResolver elResolver = this.rtCtx.getConditionResolver();
        Boolean b = elResolver.resolveBooleanExpression(condition, var_map);

        return b;
    }

    /**
     * 计算value值
     * @param token
     * @param condition
     * @throws WorkflowException
     */
    public void calculateTheAliveValue(IToken token, String condition)throws WorkflowException {

        if (!token.isAlive()) {
            return;//如果token是dead状态，表明synchronizer的joinpoint是dead状态，不需要重新计算。
        }

        //1、如果没有转移条件，默认为true
        if (condition == null || condition.trim().equals("")) {
            token.setAlive(true);
            return;
        }
        //2、default类型的不需要计算其alive值，该值由synchronizer决定
        if (condition.trim().equals(ConditionConstant.DEFAULT)) {
            return;
        }

        //3、计算EL表达式
        try{
	        boolean alive = determineTheAliveOfToken(condition, token.getProcess().getVariables());
	        token.setAlive(alive);
        }catch(Exception ex){
        	throw new WorkflowException(token.getProcess().getId(), token.getProcess().getModel(),token.getNodeId(),ex.getMessage());
        }

    }

    public String getExtentionTargetName() {
        return Transition.ExtensionTargetName;
    }

    public String getExtentionPointName() {
        return Transition.ExtensionPointTransitionEventListener;
    }

    /* (non-Javadoc)
     * @see org.fireflow.kernel.event.IEdgeInstanceEventListener#onEdgeInstanceEventFired(org.fireflow.kernel.event.EdgeInstanceEvent)
     */
    public void onEdgeEventFired(EdgeEvent e) throws WorkflowException {
        if (e.getEventType() == EdgeEvent.ON_TAKING_THE_TOKEN) {
            IToken token = e.getToken();
            ITransition transInst = (ITransition) e.getSource();
            String condition = transInst.getEdgeModel().getCondition();
            
            calculateTheAliveValue(token, condition);

            if (rtCtx.isEnableTrace() && token.isAlive()) {
                WFTransition transition = transInst.getEdgeModel();
                WFElement fromNode = transition.getFromNode();
                int minorNumber = 1;
                if (fromNode instanceof WFActivity){
                    minorNumber=2;
                }else{
                    minorNumber =1;
                }

                ProcessTrace trace = new ProcessTrace();
                trace.setProcessInstanceId(e.getToken().getProcess().getId());
                trace.setStepNum(e.getToken().getStepNumber());
                trace.setType(IProcessTrace.TRANSITION_TYPE);
                trace.setFromNodeId(transInst.getEdgeModel().getFromNode().getId());
                trace.setToNodeId(transInst.getEdgeModel().getToNode().getId());
                trace.setEdgeId(transInst.getEdgeId());
                trace.setMinorNum(minorNumber);
                //TODO wmj2003 这里应该是insert。一旦token从当前边上经过，那么就保存流程运行轨迹.
                rtCtx.getPersistenceService().saveOrUpdateProcessTrace(trace);
            }
        }

    }
}
